/*
 * Copyright [2022] [https://www.xiaonuo.vip]
 *
 * Snowy采用APACHE LICENSE 2.0开源协议，您在使用过程中，需要注意以下几点：
 *
 * 1.请不要删除和修改根目录下的LICENSE文件。
 * 2.请不要删除和修改Snowy源码头部的版权声明。
 * 3.本项目代码可免费商业使用，商业使用请保留源码和相关描述文件的项目出处，作者声明等。
 * 4.分发源码时候，请注明软件出处 https://www.xiaonuo.vip
 * 5.不可二次分发开源参与同类竞品，如有想法可联系团队xiaonuobase@qq.com商议合作。
 * 6.若您的项目无法满足以上几点，需要更多功能代码，获取Snowy商业授权许可，请在官网购买授权，地址为 https://www.xiaonuo.vip
 */
package vip.xiaonuo.biz.modular.qhhistory.service.impl;

import cn.afterturn.easypoi.cache.manager.POICacheManager;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollStreamUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
import com.alibaba.excel.write.style.column.SimpleColumnWidthStyleStrategy;
import com.alibaba.excel.write.style.row.AbstractRowHeightStyleStrategy;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.Row;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import vip.xiaonuo.biz.modular.qhhistory.entity.QhHistory;
import vip.xiaonuo.biz.modular.qhhistory.enums.FutureProducts;
import vip.xiaonuo.biz.modular.qhhistory.mapper.QhHistoryMapper;
import vip.xiaonuo.biz.modular.qhhistory.param.*;
import vip.xiaonuo.biz.modular.qhhistory.service.QhHistoryService;
import vip.xiaonuo.biz.modular.qhhistory.util.ExcelListenerUtil;
import vip.xiaonuo.common.enums.CommonSortOrderEnum;
import vip.xiaonuo.common.exception.CommonException;
import vip.xiaonuo.common.page.CommonPageRequest;
import vip.xiaonuo.common.util.CommonDownloadUtil;
import vip.xiaonuo.common.util.CommonResponseUtil;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;

/**
 * 期货数据Service接口实现类
 *
 * @author yoo
 * @date 2024/05/20 16:42
 **/
@Service
@Slf4j
public class QhHistoryServiceImpl extends ServiceImpl<QhHistoryMapper, QhHistory> implements QhHistoryService {


    @Override
    public Page<QhHistory> page(QhHistoryPageParam qhHistoryPageParam) {
        return this.page(CommonPageRequest.defaultPage(), buildQuery(qhHistoryPageParam));
    }

    private QueryWrapper<QhHistory> buildQuery(QhHistoryPageParam qhHistoryPageParam) {
        QueryWrapper<QhHistory> queryWrapper = new QueryWrapper<>();
        if (ObjectUtil.isNotEmpty(qhHistoryPageParam.getStartTradeDate()) && ObjectUtil.isNotEmpty(qhHistoryPageParam.getEndTradeDate())) {
            queryWrapper.lambda().between(QhHistory::getTradeDate, qhHistoryPageParam.getStartTradeDate(), qhHistoryPageParam.getEndTradeDate());
        }
        if (ObjectUtil.isNotEmpty(qhHistoryPageParam.getContractCode())) {
            queryWrapper.lambda().like(QhHistory::getContractCode, qhHistoryPageParam.getContractCode());
        }
        if (ObjectUtil.isNotEmpty(qhHistoryPageParam.getContractName())) {
            queryWrapper.lambda().like(QhHistory::getContractName, qhHistoryPageParam.getContractName());
        }
        if (ObjectUtil.isNotEmpty(qhHistoryPageParam.getStartLossDate()) && ObjectUtil.isNotEmpty(qhHistoryPageParam.getEndLossDate())) {
            queryWrapper.lambda().between(QhHistory::getLossDate, qhHistoryPageParam.getStartLossDate(), qhHistoryPageParam.getEndLossDate());
        }
        if (ObjectUtil.isNotEmpty(qhHistoryPageParam.getDatesource())) {
            queryWrapper.lambda().like(QhHistory::getDatesource, qhHistoryPageParam.getDatesource());
        }
        if (ObjectUtil.isNotEmpty(qhHistoryPageParam.getBatchId())) {
            queryWrapper.lambda().like(QhHistory::getBatchId, qhHistoryPageParam.getBatchId());
        }
        if (ObjectUtil.isAllNotEmpty(qhHistoryPageParam.getSortField(), qhHistoryPageParam.getSortOrder())) {
            CommonSortOrderEnum.validate(qhHistoryPageParam.getSortOrder());
            queryWrapper.orderBy(true, qhHistoryPageParam.getSortOrder().equals(CommonSortOrderEnum.ASC.getValue()),
                    StrUtil.toUnderlineCase(qhHistoryPageParam.getSortField()));
        } else {
            queryWrapper.lambda().orderByAsc(QhHistory::getTradeDate).orderByAsc(QhHistory::getContractCode);
        }
        return queryWrapper;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void add(QhHistoryAddParam qhHistoryAddParam) {
        QhHistory qhHistory = BeanUtil.toBean(qhHistoryAddParam, QhHistory.class);
        this.save(qhHistory);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void edit(QhHistoryEditParam qhHistoryEditParam) {
        QhHistory qhHistory = this.queryEntity(qhHistoryEditParam.getId());
        BeanUtil.copyProperties(qhHistoryEditParam, qhHistory);
        this.updateById(qhHistory);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void delete(List<QhHistoryIdParam> qhHistoryIdParamList) {
        // 执行删除
        this.removeByIds(CollStreamUtil.toList(qhHistoryIdParamList, QhHistoryIdParam::getId));
    }

    @Override
    public QhHistory detail(QhHistoryIdParam qhHistoryIdParam) {
        return this.queryEntity(qhHistoryIdParam.getId());
    }

    @Override
    public QhHistory queryEntity(String id) {
        QhHistory qhHistory = this.getById(id);
        if (ObjectUtil.isEmpty(qhHistory)) {
            throw new CommonException("期货数据不存在，id值为：{}", id);
        }
        return qhHistory;
    }

    @Override
    public void downloadImportQhHistoryTemplate(HttpServletResponse response) throws IOException {
        try {
            InputStream inputStream = POICacheManager.getFile("qhHistoryImportTemplate-zhengzhou.xlsx");
            byte[] bytes = IoUtil.readBytes(inputStream);
            CommonDownloadUtil.download("郑商所数据导入模板.xlsx", bytes, response);
        } catch (Exception e) {
            log.error(">>> 下载用户导入模板失败：", e);
            CommonResponseUtil.renderError(response, "下载用户导入模板失败");
        }
    }

    @Override
    public JSONObject importQhHistory(MultipartFile file) {
        File tempFile = null;
        try {
            int successCount = 0;
            int errorCount = 0;
            JSONArray errorDetail = JSONUtil.createArray();
            // 创建临时文件
            tempFile = FileUtil.writeBytes(file.getBytes(), FileUtil.file(FileUtil.getTmpDir() +
                    FileUtil.FILE_SEPARATOR + "qhHistoryImportTemplate-zhengzhou.xlsx"));
            String batchId = generateBatchId();
            //分批导入（提速1）
            AnalysisEventListener<QhHistoryImportParam> listener = ExcelListenerUtil.getListener(this.batchInsert(batchId), 100);
            // 读取excel
            List<QhHistoryImportParam> qhHistoryExcels = EasyExcel.read(tempFile, QhHistoryImportParam.class, listener)
                    .sheet()
                    .headRowNumber(2) //第3行开始读取数据
                    //异步解析（提速2）
                    .doReadSync();
            successCount += qhHistoryExcels.size();
            return JSONUtil.createObj()
                    .set("totalCount", successCount)
                    .set("successCount", successCount)
                    .set("errorCount", errorCount)
                    .set("errorDetail", errorDetail);

        } catch (Exception e) {
            log.error(">>> 导入失败：", e);
            throw new CommonException("导入失败");
        } finally {
            if (tempFile != null) {
                FileUtil.del(tempFile);
            }
        }
    }

    private Consumer<List<QhHistoryImportParam>> batchInsert(String batchId) {
        log.info("消费者");
        return excelData -> {
            List<QhHistory> qhHistories = new ArrayList<>();
            excelData.forEach(q -> {
                QhHistory qhHistory = new QhHistory();
                BeanUtil.copyProperties(q, qhHistory);
                qhHistory.setContractName(FutureProducts.containsAndGet(q.getContractCode()));
                qhHistory.setBatchId(batchId);
                qhHistory.setDatesource(ExcelListenerUtil.DATASOURCE);
                qhHistories.add(qhHistory);
            });
            //异步保存（提速3）
            CompletableFuture.runAsync(() -> this.saveBatch(qhHistories));
        };
    }

    public String generateBatchId() {
        // 获取当前日期，格式为yyyyMMdd
        String datePart = DateTime.now().toString("yyyyMMddHH");
        // 生成一个随机的4位数
        String randomPart = String.valueOf(RandomUtil.randomInt(1000, 9999));
        // 组合日期和随机部分生成批次号
        return datePart + randomPart;
    }

    @Override
    public void exportQhHistory(QhHistoryExportParam qhHistoryPageParam, HttpServletResponse response) throws IOException {
        File tempFile = null;
        try {
            String fileName = "期货数据.xlsx";
            QhHistoryPageParam param = new QhHistoryPageParam();
            BeanUtil.copyProperties(qhHistoryPageParam, param);
            QueryWrapper<QhHistory> queryWrapper = buildQuery(param);
            List<QhHistory> qhHistories = list(queryWrapper);
            List<QhHistoryExportResult> resultList = qhHistories.stream()
                    .map(r -> {
                        QhHistoryExportResult exportResult = new QhHistoryExportResult();
                        BeanUtil.copyProperties(r, exportResult);
                        return exportResult;
                    }).toList();
            if (ObjectUtil.isEmpty(resultList)) {
                throw new CommonException("无数据可导出");
            }
            // 创建临时文件
            tempFile = FileUtil.file(FileUtil.getTmpDir() + FileUtil.FILE_SEPARATOR + fileName);
            // 写excel
            EasyExcel.write(tempFile.getPath(), QhHistoryExportResult.class)
                    // 自动列宽
                    .registerWriteHandler(new SimpleColumnWidthStyleStrategy(12))
                    // 设置表头行高
                    .registerWriteHandler(new AbstractRowHeightStyleStrategy() {
                        @Override
                        protected void setHeadColumnHeight(Row row, int relativeRowIndex) {
                            if (relativeRowIndex == 0) {
                                // 表头第一行
                                row.setHeightInPoints(34);
                            } else {
                                // 表头其他行
                                row.setHeightInPoints(30);
                            }
                        }

                        @Override
                        protected void setContentColumnHeight(Row row, int relativeRowIndex) {
                            // 内容行
                            row.setHeightInPoints(20);
                        }
                    })
                    .sheet("期货数据")
                    .doWrite(resultList);
            CommonDownloadUtil.download(tempFile, response);
        } catch (Exception e) {
            log.error(">>> 导出失败：", e);
            CommonResponseUtil.renderError(response, "导出失败");
        } finally {
            if (tempFile != null) {
                FileUtil.del(tempFile);
            }
        }
    }
}
